package game 
{
	import net.flashpunk.Entity;
	import net.flashpunk.graphics.Spritemap;
	import utils.KeyCombo;
	
	// Keyboard/Mouse inputs
	import net.flashpunk.utils.Input;
	import net.flashpunk.utils.Key;
	
	import utils.SoundBoard;
	
	// HACK - only here for now, for level switching
	import net.flashpunk.FP;
	
	/**
	 * ...
	 * @author Matt Hofmann
	 */
	public class Player extends Entity 
	{
		//[Embed(source = "../../assets/naruto_standing.png")]
		[Embed(source = "../../assets/naruto_sprites.png")]
			private const imgPlayer:Class;
			public var sprPlayer:Spritemap = new Spritemap(imgPlayer, 40, 50, spriteAnimationEnd);
			
		// Static constants
		private var gspeed:Number = 0.4;	// Gravity
		private var fspeed:Number = 0.9;	// Air Friction
		private var mspeed:Number = 5;		// Maximum move speed
		private var jspeed:Number = 6.0;	// Jump
		private var teleport_distance:Number = 150;
		
		// Track key combos
		private var keycomboevents:KeyCombo;
		
		// Player properties
		private var xspeed:Number = 0;
		private var yspeed:Number = 0;
		private var onground:Boolean = true;
		private var facingright:Boolean = true;
		private var hasdoublejump:Boolean = true;
		
		// Actions which stop the Player update loop (while being "cast")
		private var teleporting:int = 0;
		private var reappearing:Boolean = false;
		private var throwing:Boolean = false;
		
		public function Player(startx:uint, starty:uint) 
		{
			sprPlayer.add("stand", [0, 1, 2, 3, 4, 5], 12, true);
			sprPlayer.add("run", [6, 7, 8, 9, 10, 11], 15, true);
			sprPlayer.add("jumping", [12, 13], 15, true);
			sprPlayer.add("falling", [14, 15], 15, true);
			sprPlayer.add("landed", [16], 15, false);
			sprPlayer.add("teleport_disappear", [18, 19, 20, 21], 30, false);
			sprPlayer.add("teleport_reappear", [21, 20], 30, false);
			sprPlayer.add("throw", [24, 25, 26, 27, 28], 20, false);
			
			//keyboard controls.
			Input.define("right", Key.RIGHT);
			Input.define("left", Key.LEFT);
			Input.define("jump", Key.UP);
			Input.define("kunai", Key.A);
			Input.define("shuriken", Key.S);
			Input.define("pinwheel", Key.D);
			
			// Set player image graphic
			graphic = sprPlayer;
			
			// Define hitbox - slightly smaller than 40x50 sprite size
			setHitbox(32, 44, -4, -3);
			
			// Init player coordinates
			this.x = startx;
			this.y = starty;
			
			// Check for key combos, such as double-tap directions
			keycomboevents = new KeyCombo();
			keycomboevents.addDoubleKeyListener(Key.RIGHT, onDoubleRight);
			keycomboevents.addDoubleKeyListener(Key.LEFT, onDoubleLeft);
		}
		
		/**
		 * Callback from 
		 */
		public function onDoubleRight():void {
			sprPlayer.play("teleport_disappear", false);
			SoundBoard.i.playSound(SoundBoard.i.sfxTeleport);
			teleporting = 1;	// 1 = right, -1 = left
		}
		
		public function onDoubleLeft():void {
			sprPlayer.play("teleport_disappear", false);
			SoundBoard.i.playSound(SoundBoard.i.sfxTeleport);
			teleporting = -1;	// 1 = right, -1 = left
		}
		
		public function spriteAnimationEnd():void {
			if (teleporting) {
				sprPlayer.play("teleport_reappear", false);
				teleportPlayer(teleporting);
				teleporting = 0;
				reappearing = true;
			}
			else if (reappearing) {
				reappearing = false;
			}
			else if (throwing) {
				throwing = false;
			}
		}
		
		public function teleportPlayer(direction:int):void
		{
			//this.x += teleport_distance * direction;
			for (var i:int = 0; i < Math.abs(teleport_distance); i += 1) {
				if (!collide("wall", x + direction, y)) {
					x += direction;
					//FP.camera.x += direction;
					Level.gameCamera.followPlayer(this);
				} else { 
					xspeed = 0; 
					break; 
				}
			}
		}
		
		public function throwKunai():void
		{
			throwing = true;
			sprPlayer.play("throw", false);
			SoundBoard.i.playSound(SoundBoard.i.sfxThrow1);
			
			FP.world.add(new Weapon(Weapon.KUNAI, x, y + 10, facingright ? 1 : -1));
		}
		
		public function throwShuriken():void
		{
			throwing = true;
			sprPlayer.play("throw", false);
			SoundBoard.i.playSound(SoundBoard.i.sfxThrow1);
			
			FP.world.add(new Weapon(Weapon.SHURIKEN, x, y + 10, facingright ? 1 : -1));
		}
		
		public function throwPinwheel():void
		{
			throwing = true;
			sprPlayer.play("throw", false);
			SoundBoard.i.playSound(SoundBoard.i.sfxThrow2);
			
			FP.world.add(new Weapon(Weapon.PINWHEEL, x, y + 15, facingright ? 1 : -1));
		}		
		
		// Registers KeyCombo entity with World, when Player is added
		override public function added():void
		{
			FP.world.add(keycomboevents);
			super.added();
		}
		
		public function getXSpeed():Number
		{
			return this.teleporting * mspeed || this.xspeed;
		}
		
		public function getYSpeed():Number
		{
			return this.yspeed;
		}
		
		override public function update():void
		{	
			// HACK: test level changes
			if (Input.check(Key.DIGIT_1)) {
				FP.world.remove(this);
				FP.world = new Level(Level.LEVEL1);
			}
			if (Input.check(Key.DIGIT_2)) {
				FP.world.remove(this);
				FP.world = new Level(Level.LEVEL2);
			}
			if (Input.check(Key.DIGIT_3)) {
				FP.world.remove(this);
				FP.world = new Level(Level.LEVEL3);
			}
			if (Input.check(Key.DIGIT_4)) {
				FP.world.remove(this);
				FP.world = new Level(Level.LEVEL4);
				SoundBoard.i.playSound(SoundBoard.i.musSong1, 0.6, 0, true);
			}
			
			// HACK: Test soundboard
			if (Input.pressed(Key.Q)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxChaa);
			}
			if (Input.pressed(Key.W)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxGahh);
			}
			if (Input.pressed(Key.E)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxHei);
			}
			if (Input.pressed(Key.R)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxSeal);
			}
			if (Input.pressed(Key.T)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxRasengan);
			}
			if (Input.pressed(Key.Y)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxNgh1);
			}
			if (Input.pressed(Key.U)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxNgh2);
			}
			if (Input.pressed(Key.I)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxThrow1);
			}
			if (Input.pressed(Key.O)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxThrow2);
			}
			if (Input.pressed(Key.P)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxKunaiCling);
			}
			if (Input.pressed(Key.LEFT_SQUARE_BRACKET)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxKageBunshin);
			}
			if (Input.pressed(Key.RIGHT_SQUARE_BRACKET)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxPoof1);
			}
			if (Input.pressed(Key.L)) {
				SoundBoard.i.playSound(SoundBoard.i.sfxPoof2);
			}
			
			// Skip entire update loop, if we are in the middle of one of these actions
			if (teleporting || reappearing) {
				return;
			}
			
			// Check if we are on the ground
			// This "restores" our ability to double jump
			onground = Boolean(collide("wall", x, y + 1));
			if (onground) {
				hasdoublejump = true;
			}
			
			
			//move/jump
			if (Input.check("right")) { 
				xspeed = mspeed;
				facingright = true;
			}
			else if (Input.check("left")) { 
				xspeed = -1 * mspeed;
				facingright = false;
			}
			else if (onground) {
				xspeed = 0;
			}
			
			sprPlayer.flipped = facingright ? false : true;
			
			if (Input.pressed("jump") && (onground || hasdoublejump)) { 
				yspeed = -jspeed; 
				
				if (!onground) {
					hasdoublejump = false;
					SoundBoard.i.playSound(SoundBoard.i.sfxJump2);
				}
				else {
					SoundBoard.i.playSound(SoundBoard.i.sfxJump1);
				}
				onground = false;
			}
			
			// Move based on x speed - check for wall collisions
			var xsign:int = xspeed < 0 ? -1 : 1;
			if (Math.abs(xspeed) > 0.1) {
				for (var i:int = 0; i < Math.abs(xspeed); i += 1) {
					if (!collide("wall", x + xsign, y)) { x += xsign; } else { xspeed = 0; break; }
				}
			}
			else {
				xspeed = 0;
			}
			
			// Move based on y speed - check for wall collisions
			var ysign:int = yspeed < 0 ? -1 : 1;
			if (Math.abs(yspeed) > 0.1) {
				for (i = 0; i < Math.abs(yspeed); i += 1) {
					if (!collide("wall", x, y + ysign)) { 
						y += ysign; 
					} 
					else { 
						// Hit a surface, up or down
						// Play sound if landed on ground 
						if (yspeed > 0) {
							SoundBoard.i.playSound(SoundBoard.i.sfxLanding);
						}
						
						yspeed = 0;  
						break; 
					}
				}
			}
			else {
				yspeed = 0;
			}
			
			// Add gravity speed, if in the air
			if (!onground) {
				yspeed += gspeed;		
			}
			
			// Skip movement animation updates, if we are doing one of these actions
			if (throwing) {
				return;
			}
			
			// Update animations
			// Do this after actual movement calculations, so that we can 
			// early-out for things like throwing graphics
			sprPlayer.flipped = facingright ? false : true;
			
			// On the ground - standing or running
			if (onground) {
				if (Math.abs(xspeed) > 0) {
					sprPlayer.play("run", false); 
				}
				else {
					sprPlayer.play("stand", false);
				}
			}
			// In air - falling or jumping
			else {
				if (yspeed > 0) {
					sprPlayer.play("falling", false); 
				}
				else {
					sprPlayer.play("jumping", false); 
				}
				
				// Apply air friction
				xspeed *= fspeed;
			}
			
			// Attacks
			// Apply these last, so that they "override" movement graphics
			if (Input.pressed("kunai") && !throwing) {
				throwKunai();	
			}
			if (Input.pressed("shuriken") && !throwing) {
				throwShuriken();	
			}
			if (Input.pressed("pinwheel") && !throwing) {
				throwPinwheel();	
			}			
		}
		
	}

}